package com.gaojinqi.base.core.jpa.impl;

import com.gaojinqi.base.common.constant.RespConst;
import com.gaojinqi.base.core.jpa.BaseRepository;
import com.gaojinqi.base.common.exception.BizRuntimeException;
import com.gaojinqi.base.common.util.BeanUtil;
import com.gaojinqi.base.common.util.FieldUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.LockModeType;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;

/**
 * 通用的基础repository接口实现类
 *
 * @author gao.jinqi
 * @date 2020-03-21
 */
@Slf4j
public class BaseRepositoryImpl<T, ID extends Serializable>
        extends SimpleJpaRepository<T, ID>
        implements BaseRepository<T, ID> {

    private final EntityManager entityManager;

    public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
    }

    @Override
    @Transactional
    public T saveOneSelective(T entity) {
        entityManager.persist(entity);
        entityManager.flush();
        return entity;
    }

    @Override
    @Transactional
    public void saveSelective(T... entities) {
        for (T entity : entities) {
            entityManager.persist(entity);
        }
        entityManager.flush();
    }

    @Override
    @Transactional
    public void saveSelective(List<T> entities) {
        for (T entity : entities) {
            entityManager.persist(entity);
        }
        entityManager.flush();
    }

    @Override
    @Transactional
    public void updateOneSelective(T entity) {

        List<Object> idList = Lists.newArrayList();
        // 获取主键字段
        List<Field> fieldList = FieldUtil.getFieldsWithAnnotationPresent(entity.getClass(), Id.class);
        for (Field field : fieldList) {
            try {
                idList.add(field.get(entity));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        // id个数
        int mapSize = idList.size();
        if (mapSize == 0) {
            throw new BizRuntimeException(RespConst.RespEnum.NULL.getCode(), "缺失编号，无法更新数据");
        }

        // 源数据
        Object source = null;

        if (mapSize == 1) {
            source = entityManager.find(entity.getClass(), idList.get(0), LockModeType.PESSIMISTIC_WRITE);
        } else {
            try {
                // 生成查询实体
                Object searchEntity = entity.getClass().newInstance();
                for (Field field : fieldList) {
                    field.set(searchEntity, field.get(entity));
                }
                source = entityManager.find(entity.getClass(), searchEntity, LockModeType.PESSIMISTIC_WRITE);
            } catch (IllegalArgumentException | InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        // 将目标源中不为空的字段过滤，将数据库中查出的数据源复制到提交的目标源中
        BeanUtil.copyNullProperties(source, entity);

        entityManager.merge(entity);
        entityManager.flush();
    }

    @Override
    @Transactional
    public void updateSelective(T... entities) {
        for (T entity : entities) {
            updateOneSelective(entity);
        }
    }

    @Override
    @Transactional
    public void updateSelective(List<T> entities) {
        for (T entity : entities) {
            updateOneSelective(entity);
        }
    }

}